package com.cci.kangdao.azureAD;

import com.cci.kangdao.utilTool.HttpUtils;
import com.cci.kangdao.utilTool.JsonUtils;
import com.microsoft.aad.msal4j.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Description: Azure AD的工具类：验证用户名+密码、获取token等
 * @Company: CTY
 * @author myc
 * @date 2018-01-11
 * @version 1.0
 */
public class AzureADTool {

	private static Logger log = Logger.getLogger(AzureADTool.class);

	/**
	 * 输入用户名+密码
	 * @param username
	 * @param password
	 * @param AUTHORITY
	 * @param RESOURCE
	 * @param CLIENT_ID
	 * @return
	 * @throws Exception
	 */
	public static IAuthenticationResult getAccessTokenFromUserCredentials(String username, String password, String AUTHORITY, String CLIENT_ID, String RESOURCE){
		PublicClientApplication pca = null;
		IAuthenticationResult result = null;
		ExecutorService service = null;
		try {
			service = Executors.newFixedThreadPool(1);
			pca = PublicClientApplication.builder(CLIENT_ID)
					.authority(AUTHORITY)
					.build();
			Set<String> scope  = Collections.singleton(RESOURCE + "/.default");
			UserNamePasswordParameters parameters =
					UserNamePasswordParameters
							.builder(scope, username, password.toCharArray())
							.build();
			result = pca.acquireToken(parameters).join();
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}finally {
			service.shutdown();
		}
		return result;
	}

	/**
	 * 根据token获取用户信息
	 *
	 * @param
	 * @return
	 */
	@Deprecated
	public static AzureUser getAzureUserbyToken(String accessToken) {
		AzureUser user = null;
		try {
			URL url = new URL("https://graph.chinacloudapi.cn/me?api-version=2013-04-05");

			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			// Set the appropriate header fields in the request header.
			conn.setRequestProperty("api-version", "2013-04-05");
			conn.setRequestProperty("Authorization", accessToken);
			conn.setRequestProperty("Accept", "application/json;odata=minimalmetadata");
			conn.setRequestProperty("Content-Type", "application/json");
			String goodRespStr = HttpClientHelper.getResponseStringFromConn(conn, true);
			/**
			 * 注释log
			 * 20230808
			 * sxt 处理Privacy Violation
			 */
			//log.info("goodRespStr ->" + goodRespStr);

			user = new AzureUser();
			JSONHelper.convertJSONObjectToDirectoryObject(new JSONObject(goodRespStr), user);

			/**
			 * 注释log
			 * 20230808
			 * sxt 处理Privacy Violation
			 */
			//log.info("userId:" + user.getObjectId() + " displayName:" + user.getDisplayName());
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return user;
	}

	/**
	 * 根据Azure的 clientId+secret 获取token
	 * @param client_id
	 * @param clientSecret
	 * @param AUTHORITY
	 * @param RESOURCE
	 * @return
	 * @throws Exception
	 */
	public static IAuthenticationResult getAccessTokenByClient(String client_id, String clientSecret,String AUTHORITY,String RESOURCE){
		IAuthenticationResult result = null;
		ExecutorService service = null;
		try {
			service = Executors.newFixedThreadPool(1);
			ConfidentialClientApplication app = ConfidentialClientApplication
					.builder(client_id, ClientCredentialFactory.createFromSecret(clientSecret))
					.authority(AUTHORITY)
					.build();


			Set<String> scope  = Collections.singleton(RESOURCE + "/.default");
			ClientCredentialParameters clientCredentialParam = ClientCredentialParameters
					.builder(scope).build();
			result = app.acquireToken(clientCredentialParam).join();
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}finally {
			service.shutdown();
		}
		return result;
	}

	/**
	 * 去Azure AD创建用户
	 *
	 * @param userName
	 * @param password
	 * @param accessToken
	 * @param tenant
	 * @return
	 */
	@Deprecated
	public static String createAzureUser(String userName, String password, String accessToken, String tenant) {

		try {
			/**
			 * 按Azure Ad创建用户json
			 */
			Map<String, Object> data = new HashMap<String, Object>();
			data.put("password", password);
			data.put("forceChangePasswordNextLogin", false);

			JSONObject obj = new JSONObject();
			obj.put("accountEnabled", true);
			obj.put("displayName", userName);
			obj.put("mailNickname", userName);
			obj.put("passwordProfile", new JSONObject(data));
			// obj.put("userPrincipalName", "Alex5@dsjsdzx.com");
			obj.put("userPrincipalName", userName + "@" + tenant);
			/**
			 * 注释log
			 * 20230808
			 * sxt 处理Privacy Violation
			 */
			//log.info("obj=======" + obj.toString());

			URL url = new URL(String.format("https://graph.chinacloudapi.cn/%s/users?api-version=2013-04-05", tenant));

			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			// Set the appropriate header fields in the request header.
			conn.setRequestProperty("api-version", "2013-04-05");
			conn.setRequestProperty("Authorization", accessToken);
			conn.setRequestProperty("Accept", "application/json;odata=minimalmetadata");
			conn.setRequestProperty("Content-Type", "application/json");
			String goodRespStr = HttpClientHelper.getResponseStringFromConn(conn, obj.toString());
			int responseCode = conn.getResponseCode();

			log.info("goodRespStr ->" + responseCode + "===>" + goodRespStr);
			if (responseCode == 201) {
				return goodRespStr;
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 去Azure AD删除用户
	 *
	 * @param
	 * @param
	 * @param accessToken
	 * @param tenant
	 * @return
	 */
	public static boolean deleteAzureUser(String userid, String RESOURCE, String accessToken, String tenant) {
	try {
			/**
			 * 按Azure Ad拼接字符串
			 */
//			String uLink = String.format(
//					"https://graph.chinacloudapi.cn/%s/users/0846104f-1516-43f5-a0ef-8e4948dbce3e?api-version=2013-04-05",
//					tenant, accessToken);
			String uLink = "https://graph.chinacloudapi.cn/"+tenant+"/users/"+userid+"?api-version=2013-04-05";
			URL url = new URL(uLink);

			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			// Set the appropriate header fields in the request header.
			conn.setRequestProperty("api-version", "2013-04-05");
			conn.setRequestProperty("Authorization", accessToken);
			conn.setRequestProperty("Accept", "application/json;odata=minimalmetadata");
			conn.setRequestMethod("DELETE");
			String goodRespStr = HttpClientHelper.getResponseStringFromConn(conn, true);
			int responseCode = conn.getResponseCode();
			log.info("goodRespStr ->" + responseCode + "===>" + goodRespStr);
			if (responseCode == 204) {
				return true;
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return false;
	}

	/**
	 * 去Azure AD修改用户密码
	 *
	 * @param userObjectId
	 * @param password
	 * @param accessToken
	 * @param tenant
	 * @return
	 */
	public static boolean chagePasswordAzureUser(String userObjectId, String password, String accessToken,
			String tenant) {

		try {
			/**
			 * 按Azure Ad修改用户密码json
			 */
			Map<String, Object> data = new HashMap<String, Object>();
			data.put("password", password);
			data.put("forceChangePasswordNextLogin", false);

			JSONObject obj = new JSONObject();
			obj.put("passwordProfile", new JSONObject(data));
			/**
			 * 注释log
			 * 20230808
			 * sxt 处理Privacy Violation
			 */
			//log.info("obj=======" + obj.toString());

			URL url = new URL(String.format("https://graph.chinacloudapi.cn/%s/users/%s/?api-version=2013-04-05",
					tenant, userObjectId));

			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			// Set the appropriate header fields in the request header.
			conn.setRequestProperty("api-version", "2013-04-05");
			conn.setRequestProperty("Authorization", accessToken);
			conn.setRequestProperty("Accept", "application/json;odata=minimalmetadata");
			conn.setRequestProperty("Content-Type", "application/json");
			conn.setRequestProperty("X-HTTP-Method", "PATCH");
			String goodRespStr = HttpClientHelper.getResponseStringFromConn(conn, obj.toString());
			int responseCode = conn.getResponseCode();
			/**
			 * 注释log
			 * 20230808
			 * sxt 处理Privacy Violation
			 */
			//log.info("goodRespStr ->" + responseCode + "===>" + goodRespStr);
			if (responseCode == 204) {
				return true;
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return false;
	}

	public static String getManagementToken(String tenant,String managementClientId,String managementClientSecret){
		StringBuffer sb = new StringBuffer("https://login.partner.microsoftonline.cn/").append(tenant).append("/oauth2/v2.0/token");
		List<NameValuePair> parameter = new ArrayList<>();
		parameter.add(new BasicNameValuePair("grant_type","client_credentials"));
		parameter.add(new BasicNameValuePair("client_id",managementClientId));
		parameter.add(new BasicNameValuePair("client_secret",managementClientSecret));
		parameter.add(new BasicNameValuePair("Scope","https://microsoftgraph.chinacloudapi.cn/.default"));
		String response = HttpUtils.postForm(sb.toString(), parameter, new ResponseHandler<String>() {
			@Override
			public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
				if (response.getStatusLine().getStatusCode() == 200) {
					HttpEntity httpEntity = response.getEntity();
					return  EntityUtils.toString(httpEntity);
				}else{
					/**
					 * 注释log
					 * 20230808
					 * sxt 处理Privacy Violation
					 */
					//log.error("AD获取token异常，response：" + response);
				}
				return null;
			}
		});
		if(StringUtils.isNotEmpty(response)){
			ManagementToken token = JsonUtils.toJavaObject(response,ManagementToken.class);
			return token.getAccessToken();
		}
		return null;
	}

	public static String addUser(String username,String password,String tenant,String token){
		try {
			String url = "https://microsoftgraph.chinacloudapi.cn/v1.0/users";
			Map<String, Object> data = new HashMap<String, Object>();
			data.put("password", password);
			data.put("forceChangePasswordNextSignIn", false);
			JSONObject obj = new JSONObject();
			obj.put("accountEnabled", true);
			obj.put("displayName", username);
			obj.put("mailNickname", username);
			obj.put("passwordProfile", new JSONObject(data));
			obj.put("userPrincipalName", username  +"@"+ tenant);
			Header auth = new BasicHeader("Authorization","Bearer " + token);
			String response = HttpUtils.postJson(url, obj.toString(),new ResponseHandler<String>(){
				@Override
				public String handleResponse(HttpResponse response)
						throws ClientProtocolException, IOException {
					if (response.getStatusLine().getStatusCode() == 201) {
						HttpEntity httpEntity = response.getEntity();
						return  EntityUtils.toString(httpEntity);
					}else if(response.getStatusLine().getStatusCode() == 401){
						/**
						 * 注释log
						 * 20230808
						 * sxt 处理Privacy Violation
						 */
                        //log.warn("AD增加用户401异常重试，response：" + response + "，token：" + token);
                        return addUser(username,password,tenant,token);
                    }else {
						/**
						 * 注释log
						 * 20230808
						 * sxt 处理Privacy Violation
						 */
						//log.error("AD增加用户发生异常，response：" + response + "，token：" + token);
						log.error("AD增加用户发生异常，response：" + response);
					}
					return null;
				}
			},auth);
			return response;
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static String getUser(String username,String tenant,String token){
		StringBuffer sb = new StringBuffer("https://microsoftgraph.chinacloudapi.cn/v1.0/users/").append(username).append("@").append(tenant);
		Header authorizationHeader = new BasicHeader("Authorization","Bearer "+token);
		String response =HttpUtils.get(sb.toString(), new ResponseHandler<String>() {
			@Override
			public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
				if (response.getStatusLine().getStatusCode() == 200) {
					HttpEntity httpEntity = response.getEntity();
					return  EntityUtils.toString(httpEntity);
				}
				if(response.getStatusLine().getStatusCode() == 404){
					log.warn("AD获取用户查无用户资源，response：" + response);
				}else if(response.getStatusLine().getStatusCode() == 401){
					/**
					 * 注释log
					 * 20230808
					 * sxt 处理Privacy Violation
					 */
					//log.warn("AD获取用户401异常重试，response：" + response + "，token：" + token);
					return getUser(username,tenant,token);
				}else{
					/**
					 * 注释log
					 * 20230808
					 * sxt 处理Privacy Violation
					 */
                    //log.error("AD获取用户发生异常，response：" + response + "，token：" + token);
                    log.error("AD获取用户发生异常，response：" + response);
                }
				return null;
			}
		},authorizationHeader);
		return response;
	}

	public static Boolean lockUser(String tenant,String username,String token){
		Map<String,Object> userProfile = new HashMap<>();
		userProfile.put("accountEnabled",false);
		return updateUserProfile(tenant,username,token,userProfile);
	}

	public static boolean modifyUserPassword(String tenant,String username,String token,String password){
		Map<String,Object> userProfile = new HashMap<>();
		Map<String,Object> passwordProfile = new HashMap<>();
		passwordProfile.put("password",password);
		passwordProfile.put("forceChangePasswordNextSignIn",false);
		userProfile.put("passwordProfile",passwordProfile);
		return updateUserProfile(tenant,username,token,userProfile);
	}

	public static boolean updateCustomAttributes(String tenant, String username, String token, String unionid_field, String workgroupid_field, String SWRegExpire_field, String unionid, String workgroupid, String SWRegExpire) {
		Map<String, Object> profile = new HashMap<>();
		if(null != unionid) {
			profile.put(unionid_field, unionid);
		}
		if(null != workgroupid) {
			profile.put(workgroupid_field, workgroupid);
		}
		if(null != SWRegExpire) {
			profile.put(SWRegExpire_field, SWRegExpire);
		}
		return updateUserProfile(tenant, username, token, profile);
	}

	private static boolean updateUserProfile(String tenant,String username,String token,Map<String,Object> profile){
		StringBuffer sb = new StringBuffer("https://microsoftgraph.chinacloudapi.cn/v1.0/users/").append(username).append("@").append(tenant);
		Header authorizationHeader = new BasicHeader("Authorization","Bearer "+token);
		Boolean flag  = HttpUtils.patchJson(sb.toString(), JsonUtils.toJsonString(profile),new ResponseHandler<Boolean>() {
			@Override
			public Boolean handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
				if (response.getStatusLine().getStatusCode() == 204) {
					return true;
				}else {
					/**
					 * 注释log
					 * 20230808
					 * sxt 处理Privacy Violation
					 */
					//log.error(String.format("AD修改用户异常，username:%s  response:%s", username, response));
					log.error("AD修改用户异常，response：" + response);
					return false;
				}
			}
		},authorizationHeader);
		return flag;
	}

}
